﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Runtime.CompilerServices;
using System.Text;
using System.Windows;
using Flurl;
using Newtonsoft.Json;
using WebSocket4Net;
using ZilLion.Core.ConfigManager.Manager;
using ZilLion.Core.Log;
using ZilLion.Core.TaskManager.Workstation.Annotations;
using ZilLion.Core.TaskManager.Workstation.Thread;
using ZilLion.Core.Unities.UnitiesMethods;
using ZilLion.TaskManager.Core.Infrastructure;
using ZilLion.TaskManager.Entity.Config;
using ZilLion.TaskManager.Entity.Response;
using ZilLion.TaskManager.Entity.SokectMessage;
using LogDto = ZilLion.Core.TaskManager.Workstation.Data.LogDto;

namespace ZilLion.Core.TaskManager.Workstation
{
    /// <summary>
    ///     ServiceManager.xaml 的交互逻辑
    /// </summary>
    public partial class ServiceManager : Window, INotifyPropertyChanged
    {
        private bool _containerServiceStoped = true;
        private WindowState _currentWindowState;
        private bool _webServiceStoped = true;

        public ServiceManager()
        {
            Application.Current.DispatcherUnhandledException += (sender, args) =>
            {
                ZilLionLogManager.Instance().Error(args.Exception);
                UiThread.Invoke(() =>
                {
                    InfoLogList.Add(new LogDto
                    {
                        LogMessage = $"{args.Exception.Message}{Environment.NewLine}{args.Exception.StackTrace}",
                        Loglevel = Loglevel.Error,
                        LogTime = DateTime.Now
                    });
                });
            };
            InitializeComponent();
            DataContext = this;
        }

        public WindowState CurrentWindowState
        {
            get => _currentWindowState;
            set
            {
                _currentWindowState = value;
                ShowInTaskbar = _currentWindowState != WindowState.Minimized;
                OnPropertyChanged(nameof(CurrentWindowState));
            }
        }

        /// <summary>
        ///     端口显示文案
        /// </summary>
        public string ServiceInfoText
        {
            get => _serviceInfoText;
            set
            {
                _serviceInfoText = value;
                OnPropertyChanged(nameof(ServiceInfoText));
            }
        }

        /// <summary>
        ///     宿主服务情况
        /// </summary>
        public string WatcherInfoText
        {
            get => _watcherInfoText;
            set
            {
                _watcherInfoText = value;
                OnPropertyChanged(nameof(WatcherInfoText));
            }
        }

        /// <summary>
        ///     宿主服务情况
        /// </summary>
        public string ContainerInfoText
        {
            get => _containerInfoText;
            set
            {
                _containerInfoText = value;
                OnPropertyChanged(nameof(ContainerInfoText));
            }
        }

        /// <summary>
        ///     服务是否已启动
        /// </summary>
        public bool WebServiceStarted => !WebServiceStoped;

        /// <summary>
        ///     服务是否已启动
        /// </summary>
        public bool WebServiceStoped
        {
            get => _webServiceStoped;
            set
            {
                _webServiceStoped = value;
                OnPropertyChanged(nameof(WebServiceStoped));
                OnPropertyChanged(nameof(WebServiceStarted));
            }
        }

        /// <summary>
        ///     服务是否已启动
        /// </summary>
        public bool ContainerServiceStoped
        {
            get => _containerServiceStoped;
            set
            {
                _containerServiceStoped = value;
                OnPropertyChanged(nameof(ContainerServiceStoped));
                OnPropertyChanged(nameof(ContainerServiceStarted));
            }
        }

        /// <summary>
        ///     服务是否已启动
        /// </summary>
        public bool ContainerServiceStarted => !ContainerServiceStoped;


        /// <summary>
        ///     配置
        /// </summary>
        public TaskManagerWorkStationArgs WorkStationConfig { get; set; }


        public bool ServiceStartable
        {
            get => _serviceStartable;
            set => _serviceStartable = value;
        }

        private void MonitorService()
        {
            WpfTask.FactoryStartNew(() =>
            {
                while (true)
                {
                    try
                    {
                        using (var watcherProcess = Process.GetProcessesByName(WorkStationConfig.ServicePname)
                            .FirstOrDefault(x => x.Id == WorkStationConfig.ServicePid))
                        {
                            if (watcherProcess != null && !watcherProcess.HasExited)
                                UiThread.Invoke(() =>
                                {
                                    ContainerServiceStoped = false;
                                    if (watcherProcess != null)
                                        WatcherInfoText =
                                            // ReSharper disable once AccessToDisposedClosure
                                            $"运行中,PID:{WorkStationConfig.ServicePid},占用内存:{watcherProcess.WorkingSet64 / 1024 / 1024}MB,开启线程:{watcherProcess.Threads.Count}个";
                                });
                            else
                                UiThread.Invoke(() =>
                                {
                                    WatcherInfoText = $"已停止!";
                                    if (!ContainerServiceStoped)
                                        InfoLogList.Add(new LogDto
                                        {
                                            LogMessage = $"任务宿主服务已停止",
                                            Loglevel = Loglevel.Warn,
                                            LogTime = DateTime.Now
                                        });

                                    ContainerServiceStoped = true;
                                });
                        }

                        using (var containerProcess = Process.GetCurrentProcess())
                        {
                            if (!containerProcess.HasExited)
                                UiThread.Invoke(() =>
                                {
                                    ContainerInfoText =
                                        $"运行中,PID:{containerProcess.Id},占用内存:{containerProcess.WorkingSet64 / 1024 / 1024}MB,开启线程:{containerProcess.Threads.Count}个";
                                });
                        }
                    }
                    catch (Exception e)
                    {
                        UiThread.Invoke(() =>
                        {
                            InfoLogList.Add(new LogDto
                            {
                                LogMessage = $"{e.Message}{Environment.NewLine}{e.StackTrace}",
                                Loglevel = Loglevel.Error,
                                LogTime = DateTime.Now
                            });
                        });
                        continue;
                    }

                    System.Threading.Thread.Sleep(2000);
                }
            });
        }

        private void ClearLogs(object sender, RoutedEventArgs e)
        {
            if (TabSelectIndex == 0)
                InfoLogList.Clear();
            if (TabSelectIndex == 1)
                ErrorLogList.Clear();
            if (TabSelectIndex == 2)
                WranLogList.Clear();
            if (TabSelectIndex == 3)
                TranceLogList.Clear();
        }

        private WebSocket CreateWebSocketConnection()
        {
            var tryConnectCount = 0;
            WebSocket result = null;
            while (true)
                if (tryConnectCount > 10)
                {
                    UiThread.Invoke(() =>
                    {
                        InfoLogList.Add(new LogDto
                        {
                            LogMessage = $"Socket服务器尝试连接10次都失败",
                            Loglevel = Loglevel.Warn,
                            LogTime = DateTime.Now
                        });
                    });
                    return null;
                }
                else
                {
                    var url = Url.Combine(TaskManagerGlobalSetting.GetInstance().ManagerServiceHost, "Api",
                        "Jwt",
                        "GetJwt", "websocket"
                    );
                    var token = HttpHelper.HttpRequestPost<Dictionary<string, string>, TokenResponse>(url,
                        new Dictionary<string, string>
                        {
                            {
                                "clinetKey", JsonConvert.SerializeObject(new SocketKeyDto
                                {
                                    ClientNo = ZilLionConfigurationManager
                                        .GetConfigInstance<TaskManagerCommonConfig>().ClientNo,
                                    ClientType = "Workstation"
                                })
                            }
                        });
                    if (token?.Token.IsNotNullOrEmpty() ?? false)
                    {
                        var sockethost = Url.Combine(TaskManagerGlobalSetting.GetInstance().ManagerServiceHost,
                            "websocket",
                            "TaskPlatform"
                        ).ToLower().Replace("http:", "ws:").Replace("https:", "ws:");
                        result = new WebSocket($"{sockethost}?token={token?.Token}");
                        result.Opened += (s, arg) =>
                        {
                            UiThread.Invoke(() =>
                            {
                                InfoLogList.Add(new LogDto
                                {
                                    LogMessage = $"Socket服务器连接成功",
                                    Loglevel = Loglevel.Success,
                                    LogTime = DateTime.Now
                                });
                            });
                        };
                        result.Error += (s, arg) =>
                        {
                            UiThread.Invoke(() =>
                            {
                                InfoLogList.Add(new LogDto
                                {
                                    LogMessage = $"{arg.Exception}",
                                    Loglevel = Loglevel.Error,
                                    LogTime = DateTime.Now
                                });
                            });
                        };
                        result.Closed += (s, arg) =>
                        {
                            UiThread.Invoke(() =>
                            {
                                InfoLogList.Add(new LogDto
                                {
                                    LogMessage = $"Socket连接已关闭,正在尝试重新连接...",
                                    Loglevel = Loglevel.Warn,
                                    LogTime = DateTime.Now
                                });
                                 CreateWebSocketConnection();
                            });
                        };
                        result.MessageReceived += (s, arg) =>
                        {
                            if (arg.Message.IsNotNullOrEmpty())
                            {
                                var message = JsonConvert.DeserializeObject<SocketMessage>(arg.Message);

                                #region TASKCLIENTLOG

                                if (message.MessageType.ToUpper() == "TASKCLIENTLOG")
                                {
                                    var log = JsonConvert.DeserializeObject<LogDto>(message.Data);
                                    if (log != null)
                                        UiThread.Invoke(() =>
                                        {
                                            switch (log.Loglevel)
                                            {
                                                case Loglevel.Trace:
                                                    TranceLogList.Add(log);
                                                    break;
                                                case Loglevel.Info:
                                                    InfoLogList.Add(log);
                                                    break;
                                                case Loglevel.Warn:
                                                    WranLogList.Add(log);
                                                    break;
                                                case Loglevel.Success:
                                                    InfoLogList.Add(log);
                                                    break;
                                                case Loglevel.Error:
                                                    ErrorLogList.Add(log);
                                                    break;
                                                default:
                                                    InfoLogList.Add(log);
                                                    break;
                                            }
                                        });
                                }

                                #endregion
                            }
                        };
                        result.Open();
                        return result;
                    }
                    System.Threading.Thread.Sleep(1000);
                    tryConnectCount++;
                }
        }

        
        private void ServiceManager_OnLoaded(object sender, RoutedEventArgs e)
        {
        }

        private void ServiceManager_OnInitialized(object sender, EventArgs e)
        {
            var configcode = Environment.GetCommandLineArgs();
            ShowInTaskbar = true;
            _currentWindowState = WindowState.Normal;


            try
            {
                if (configcode.Any() && configcode.Length > 1)
                {
                    var realconfig = configcode[1].DecodeBase64();
                    InfoLogList.Add(new LogDto
                    {
                        LogMessage = $"服务配置:{realconfig}",
                        Loglevel = Loglevel.Info,
                        LogTime = DateTime.Now
                    });
                    WorkStationConfig =
                        JsonConvert.DeserializeObject<TaskManagerWorkStationArgs>(realconfig);
                }
                else
                {
                    WorkStationConfig = new TaskManagerWorkStationArgs
                    {
                        ServicePid = 0,
                        CommonConfig = ZilLionConfigurationManager.GetConfigInstance<TaskManagerCommonConfig>(),
                        ServicePname = "未知",
                        WorkStationConfig =
                            ZilLionConfigurationManager.GetConfigInstance<TaskManagerWorkStationConfig>()
                    };
                }


                if (WorkStationConfig != null)
                {
                    MonitorService();
                    ServiceInfoText = "已关闭";
                    _serviceStartable = true;
                }
            }
            catch (Exception exception)
            {
                UiThread.Invoke(() =>
                {
                    InfoLogList.Add(new LogDto
                    {
                        LogMessage = $"{exception.Message}{Environment.NewLine}{exception.StackTrace}",
                        Loglevel = Loglevel.Error,
                        LogTime = DateTime.Now
                    });
                });
                var configLines = string.Empty;
                configcode.Aggregate(configLines, (current, arg) => $"{current}{current}:{arg}{Environment.NewLine}");

                InfoLogList.Add(new LogDto
                {
                    LogMessage = $"服务配置:{configLines} 解析失败",
                    Loglevel = Loglevel.Error,
                    LogTime = DateTime.Now
                });
                _serviceStartable = false;
            }
            StartWebService();
        }

        private bool CheckPortInUse(int port)
        {
            var inUse = false;

            var ipProperties = IPGlobalProperties.GetIPGlobalProperties();
            var ipEndPoints = ipProperties.GetActiveTcpListeners();

            foreach (var endPoint in ipEndPoints)
                if (endPoint.Port == port)
                {
                    inUse = true;
                    break;
                }
            return inUse;
        }

        #region 控制台输出属性

        public ObservableCollection<LogDto>TranceLogList { get; set; } = new ObservableCollection<LogDto>();


        public ObservableCollection<LogDto> WranLogList { get; set; } = new ObservableCollection<LogDto>();

        public ObservableCollection<LogDto> InfoLogList { get; set; } = new ObservableCollection<LogDto>();


        public ObservableCollection<LogDto> ErrorLogList { get; set; } = new ObservableCollection<LogDto>();
        public int TabSelectIndex { get; set; } = 0;

        #endregion


        #region INotifyPropertyChangedImp

        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion

        #region 方法

        private void StartContainerService()

        {
            try
            {
                if (WinServiceHelper.IsWindowsServiceInstalled(WorkStationConfig.CommonConfig.ServiceDisplayName) &&
                    !WinServiceHelper.IsStart(WorkStationConfig.CommonConfig.ServiceDisplayName))
                    WinServiceHelper.StartService(WorkStationConfig.CommonConfig.ServiceDisplayName);
                ContainerServiceStoped = false;
                InfoLogList.Add(new LogDto
                {
                    LogMessage = "任务宿主服务正在启动",
                    Loglevel = Loglevel.Success,
                    LogTime = DateTime.Now
                });
            }
            catch (Exception e)
            {
                UiThread.Invoke(() =>
                {
                    InfoLogList.Add(new LogDto
                    {
                        LogMessage = $"{e.Message}{Environment.NewLine}{e.StackTrace}",
                        Loglevel = Loglevel.Error,
                        LogTime = DateTime.Now
                    });
                });

                InfoLogList.Add(new LogDto
                {
                    LogMessage = "任务宿主服务开启失败,详情请查看错误日志!",
                    Loglevel = Loglevel.Error,
                    LogTime = DateTime.Now
                });
            }
        }

        private void StopContainerService()

        {
            try
            {
                if (WinServiceHelper.IsWindowsServiceInstalled(WorkStationConfig.CommonConfig.ServiceDisplayName) &&
                    WinServiceHelper.IsStart(WorkStationConfig.CommonConfig.ServiceDisplayName))
                    WinServiceHelper.StopService(WorkStationConfig.CommonConfig.ServiceDisplayName);

                using (var containerProcess = Process.GetProcessesByName(WorkStationConfig.ServicePname)
                    .FirstOrDefault(x => x.Id == WorkStationConfig.ServicePid))
                {
                    containerProcess?.Kill();
                }

                ContainerServiceStoped = true;
                InfoLogList.Add(
                    new LogDto {LogMessage = "任务宿主服务已关闭", Loglevel = Loglevel.Warn, LogTime = DateTime.Now});
            }
            catch (Exception e)
            {
                UiThread.Invoke(() =>
                {
                    InfoLogList.Add(new LogDto
                    {
                        LogMessage = $"{e.Message}{Environment.NewLine}{e.StackTrace}",
                        Loglevel = Loglevel.Error,
                        LogTime = DateTime.Now
                    });
                });
                InfoLogList.Add(new LogDto
                {
                    LogMessage = "任务宿主服务关闭失败,详情请查看错误日志!",
                    Loglevel = Loglevel.Error,
                    LogTime = DateTime.Now
                });
            }
        }

        /// <summary>
        ///     servicePid
        /// </summary>
        private int _serivcePid;

        private Process _webserviceprocess;
        private string _serivceName;

        private void StartWebService()

        {
            try
            {
                if (_serviceStartable)
                {
                    if (ZilLionConfigurationManager.GetConfigInstance<TaskManagerWorkStationConfig>().PipeServiceHost
                        .IsNullOrEmpty())
                    {
                        if (CheckPortInUse(12252))
                        {
                            MessageBox.Show("管道服务端口12252已被占用,无法启动服务!", "错误", MessageBoxButton.OK,
                                MessageBoxImage.Error);
                            InfoLogList.Add(new LogDto
                            {
                                LogMessage = $"管道服务端口12252已被占用,无法启动服务!",
                                Loglevel = Loglevel.Error,
                                LogTime = DateTime.Now
                            });
                            return;
                        }

                        _webserviceprocess = new Process
                        {
                            StartInfo =
                            {
                                FileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "WebService",
                                    "ZilLion.Service.Core.App.exe"),
                                Arguments = "12252"
                            }
                        };
                        if (!WorkStationConfig.WorkStationConfig.ShowShell)
                        {
                            _webserviceprocess.StartInfo.CreateNoWindow = true;
                            _webserviceprocess.StartInfo.UseShellExecute = false;
                        }
                        _webserviceprocess.Start();
                        _serivcePid = _webserviceprocess.Id;
                        _serivceName = _webserviceprocess.ProcessName;
                        System.Threading.Thread.Sleep(2000); //线程睡2s,保证服务开启
                    }
                    WebServiceStoped = false;
                    InfoLogList.Add(new LogDto
                    {
                        LogMessage = $"作业服务管道启动成功,PID:{_serivcePid},进程名:{_serivceName}",
                        Loglevel = Loglevel.Success,
                        LogTime = DateTime.Now
                    });
                    TaskManagerBootstrapper.NodeHeartBeatMonitorAction = response =>
                    {
                        UiThread.Invoke(() =>
                        {
                            if (response != null)
                                if (response.IsSuccess)
                                {
                                    ServiceInfoText =
                                        $"运行中,PID:{response.ServicePid},占用内存{response.ServiceWorkingSet}MB,启动线程{response.ServiceThreadsCount}个,端口:12252";
                                }
                                else
                                {
                                    ServiceInfoText =
                                        $"服务异常!,端口:12252";
                                    InfoLogList.Add(
                                        new LogDto
                                        {
                                            LogMessage = response.Errormodel.ErrMessage,
                                            Loglevel = Loglevel.Error,
                                            LogTime = DateTime.Now
                                        });
                                }
                            else
                                InfoLogList.Add(
                                    new LogDto
                                    {
                                        LogMessage = "发送节点心跳失败!",
                                        Loglevel = Loglevel.Error,
                                        LogTime = DateTime.Now
                                    });
                        });
                    };

                    CreateWebSocketConnection(); //连接Socket
                    TaskManagerBootstrapper.Run();
                }
                else
                {
                    WebServiceStoped = true;
                    InfoLogList.Add(
                        new LogDto {LogMessage = "配置获取失败,服务不能启动", Loglevel = Loglevel.Error, LogTime = DateTime.Now});
                }
            }
            catch (Exception e)
            {
                WebServiceStoped = true;
                InfoLogList.Add(
                    new LogDto
                    {
                        LogMessage = $"{e.Message}{Environment.NewLine}{e.StackTrace}",
                        Loglevel = Loglevel.Error,
                        LogTime = DateTime.Now
                    });
            }
        }

        private void StopWebService()

        {
            using (var serviceProcess = Process.GetProcessesByName(_serivceName)
                .FirstOrDefault(x => x.Id == _serivcePid))
            {
                if (serviceProcess != null)
                    if (!serviceProcess.HasExited)
                        serviceProcess.Kill();
            }
            TaskManagerBootstrapper.Stop();
            WebServiceStoped = true;
            InfoLogList.Add(new LogDto {LogMessage = "作业服务管道已关闭", Loglevel = Loglevel.Warn, LogTime = DateTime.Now});
        }

        #endregion

        #region 事件

        private void ServiceManager_OnClosing(object sender, CancelEventArgs e)
        {
            if (ContainerServiceStarted)
            {
                MessageBox.Show("宿主服务未关闭,此时关闭服务面板可能会引起系统错误,请关闭宿主服务后重试!", "警告", MessageBoxButton.OK,
                    MessageBoxImage.Warning);
                e.Cancel = true;
            }
            else
            {
                try
                {
                    {
                        TaskManagerBootstrapper.Stop();
                        using (var serviceProcess = Process.GetProcessesByName(_serivceName)
                            .FirstOrDefault(x => x.Id == _serivcePid))
                        {
                            if (serviceProcess != null)
                                if (!serviceProcess.HasExited)
                                    serviceProcess.Kill();
                        }
                        System.Threading.Thread.Sleep(1000);
                    }
                }
                finally
                {
                    Process.GetCurrentProcess().Kill();
                }
            }
        }

        private void OnOpenMenuItemClick(object sender, RoutedEventArgs e)
        {
            if (CurrentWindowState != WindowState.Minimized) return;
            CurrentWindowState = WindowState.Normal;
            WindowStartupLocation = WindowStartupLocation.CenterScreen;
        }

        private void OnHideMenuItemClick(object sender, RoutedEventArgs e)
        {
            if (CurrentWindowState != WindowState.Minimized)
                CurrentWindowState = WindowState.Minimized;
        }

        /// <summary>
        ///     是否可以启动服务 当成功加载配置之后
        /// </summary>
        private bool _serviceStartable;

        private string _containerInfoText;
        private string _watcherInfoText;
        private string _serviceInfoText;

        /// <summary>
        ///     服务停止按钮事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnStartContainerService(object sender, RoutedEventArgs e)
        {
            StartContainerService();
        }

        /// <summary>
        ///     服务停止按钮事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnStopContainerService(object sender, RoutedEventArgs e)
        {
            StopContainerService();
        }

        /// <summary>
        ///     服务启动事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnWebServiceStart(object sender, RoutedEventArgs e)
        {
            StartWebService();
        }

        /// <summary>
        ///     服务停止按钮事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnWebServiceStop(object sender, RoutedEventArgs e)
        {
            StopWebService();
        }

        /// <summary>
        ///     配置按钮事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnConfigButtonClick(object sender, RoutedEventArgs e)
        {
            var configpath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "zlsetting.json");
            if (File.Exists(configpath))
                try
                {
                    Process.Start("notepad.exe", configpath);
                }
                catch (Exception)
                {
                    MessageBox.Show("打开文件失败,请去程序目录手动打开!", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            else
                MessageBox.Show("配置文件缺失!", "警告", MessageBoxButton.OK, MessageBoxImage.Warning);
        }

        /// <summary>
        ///     复制全部日志
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnCopyAllClick(object sender, RoutedEventArgs e)
        {
            var list = new List<LogDto>();
            if (TabSelectIndex == 0)
                list.AddRange(InfoLogList);
            if (TabSelectIndex == 1)
                list.AddRange(ErrorLogList);
            if (TabSelectIndex == 2)
                list.AddRange(WranLogList);
            if (TabSelectIndex == 3)
                list.AddRange(TranceLogList);

            var builder = new StringBuilder();
            foreach (var log in list)
                builder.AppendLine(log.ToString());
            var result = builder.ToString();
            if (builder.ToString().IsNotNullOrEmpty())
                Clipboard.SetDataObject(result);
        }

        /// <summary>
        ///     配置task
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnSetTaskClick(object sender, RoutedEventArgs e)
        {
            Process.Start($"http://localhost:12252/");
        }

        #endregion
    }
}